/**
 * Copyright (c) 2011-2016, James Zhan 詹波 (jfinal@126.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jfinal.mvc;

import javax.servlet.ServletContext;

import com.jfinal.config.Constants;
import com.jfinal.config.Plugins;
import com.jfinal.config.Smart4jConfig;
import com.jfinal.config.Routes;
import com.jfinal.kit.PathKit;
import com.jfinal.mvc.render.RenderFactory;
import com.jfinal.plugin.IPlugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

/**
 * JFinal，完成项目的初始化工作
 */
public final class Smart4j {

	private final Constants constants = new Constants();
	private final Routes routes = new Routes() {
		public void config() {
		}
	};
	private final Plugins plugins = new Plugins();

	private final ActionMapping actionMapping = new ActionMapping();
	private ServletContext servletContext;
	private String contextPath;

	private static final Smart4j me = new Smart4j();

	private Smart4j() {
	}

	public static Smart4j me() {
		return me;
	}

	boolean init(Smart4jConfig jfinalConfig, ServletContext servletContext) {
		this.servletContext = servletContext;
		this.contextPath = servletContext.getContextPath();
		initPathUtil();

//		Config.configJFinal(jfinalConfig); // start plugin and init log factory in this method
		jfinalConfig.configConstant(constants);
		jfinalConfig.configRoute(routes);
		jfinalConfig.configPlugin(plugins);

		initActionMapping();
		initRender();
		startPlugins();

		return true;
	}

	private void initPathUtil() {
		String path = servletContext.getRealPath("/");
		PathKit.setWebRootPath(path);
	}

	private void initRender() {
		RenderFactory.me().init(constants, servletContext);
	}

	private void initActionMapping() {
		actionMapping.init(routes);
	}

	public Constants getConstants() {
		return constants;
	}

	public Routes getRoutes() {
		return routes;
	}

	public Map<String, Action> getActionMapping() {
		return actionMapping.getActionMapping();
	}

	public ActionHandler getActionHandler() {
		return new ActionHandler(actionMapping);
	}

	public String getContextPath() {
		return contextPath;
	}

	public ServletContext getServletContext() {
		return servletContext;
	}

	private void startPlugins() {
		List<IPlugin> pluginList = plugins.getPluginList();
		if (pluginList == null)
			return ;

		for (IPlugin plugin : pluginList) {
			try {
				// process ActiveRecordPlugin devMode
				if (plugin instanceof com.jfinal.plugin.activerecord.ActiveRecordPlugin) {
					com.jfinal.plugin.activerecord.ActiveRecordPlugin arp = (com.jfinal.plugin.activerecord.ActiveRecordPlugin)plugin;
					if (arp.getDevMode() == null)
						arp.setDevMode(constants.getDevMode());
				}

				if (plugin.start() == false) {
					String message = "Plugin start error: " + plugin.getClass().getName();
					LOGGER.error(message);
					throw new RuntimeException(message);
				}
			}
			catch (Exception e) {
				String message = "Plugin start error: " + plugin.getClass().getName() + ". \n" + e.getMessage();
				LOGGER.error(message, e);
				throw new RuntimeException(message, e);
			}
		}
	}

	void stopPlugins() {
		List<IPlugin> pluginList = plugins.getPluginList();
		if (pluginList != null) {
			for (int i=pluginList.size()-1; i >= 0; i--) {		// stop plugins
				boolean success = false;
				try {
					success = pluginList.get(i).stop();
				}
				catch (Exception e) {
					success = false;
					LOGGER.error(e.getMessage(), e);
				}
				if (!success) {
					System.err.println("Plugin stop error: " + pluginList.get(i).getClass().getName());
				}
			}
		}
	}
	private static final Logger LOGGER = LoggerFactory.getLogger(Smart4j.class);
}
